package cn.liutao.bill.service;

import cn.hutool.core.util.StrUtil;
import cn.liutao.bill.vo.*;
import cn.liutao.common.enums.BillEnum;
import cn.liutao.common.enums.CommonEnum;
import cn.liutao.common.enums.OrderEnum;
import cn.liutao.common.utils.ServletUtils;
import cn.liutao.dish.entity.po.Cuisine;
import cn.liutao.dish.entity.po.Dish;
import cn.liutao.dish.entity.vo.DishVo;
import cn.liutao.dish.mapper.CuisineMapper;
import cn.liutao.dish.mapper.DishMapper;
import cn.liutao.order.entity.po.OrderBill;
import cn.liutao.order.entity.vo.CartVo;
import cn.liutao.order.mapper.OrderBillMapper;
import com.alibaba.fastjson.JSONArray;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.relation.RelationManager;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Year;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.liutao.dish.entity.po.table.CuisineTableDef.CUISINE;
import static cn.liutao.dish.entity.po.table.DishTableDef.DISH;
import static cn.liutao.order.entity.po.table.OrderBillTableDef.ORDER_BILL;
import static com.mybatisflex.core.query.QueryMethods.*;

/**
 * @author liutao
 * @Description 报表业务代码（新逻辑）
 * @date 2023/12/13
 */
public class BillService {


    private static volatile BillService instance;
    private OrderBillMapper orderBillMapper;
    private CuisineMapper cuisineMapper;
    private DishMapper dishMapper;

    private BillService() {
        orderBillMapper = ServletUtils.getMapper(OrderBillMapper.class);
        cuisineMapper = ServletUtils.getMapper(CuisineMapper.class);
        dishMapper = ServletUtils.getMapper(DishMapper.class);
    }

    public static BillService getInstance() {
        if (instance == null) {
            synchronized (BillService.class) {
                if (instance == null) {
                    instance = new BillService();
                }
            }
        }
        return instance;
    }

    /**
     * 销售总览
     * @return
     */
    public OverallVo getOverall() {
        OverallVo overallVo = new OverallVo();
        //获取年销售情况
        OverallVo yearOverall = getOverallByOrderby(BillEnum.BILL_ORDER_BY_YEAR.getIntValue(),null);
        //获取月销售情况
        OverallVo monthOverall = getOverallByOrderby(BillEnum.BILL_ORDER_BY_MONTH.getIntValue(),null);
        //获取日销售情况
        OverallVo dayOverall = getOverallByOrderby(BillEnum.BILL_ORDER_BY_DAY.getIntValue(),null);

        overallVo.setDayCustom(dayOverall.getDayCustom());
        overallVo.setDayQuantity(dayOverall.getDayQuantity());
        overallVo.setMonthCustom(monthOverall.getMonthCustom());
        overallVo.setMonthQuantity(monthOverall.getMonthQuantity());
        overallVo.setYearCustom(yearOverall.getYearCustom());
        overallVo.setYearQuantity(yearOverall.getYearQuantity());

        return overallVo;
    }


    /**
     * 菜系销量排行
     * @return
     */
    public List<RankVO> getCuisineRank(Integer orderBy) {
        //获取所有订单记录
        List<OrderBill> billList = getOrderBillList(orderBy);
        //获取购物车信息
        List<CartVo> cartInfo = getCartInfo(billList);
        //获取所有菜系列表
        List<Cuisine> cuisineList = cuisineMapper.selectListByQuery(QueryWrapper.create().where(CUISINE.STATUS.eq(CommonEnum.STATUS_ON.getIntValue())));
        //遍历菜系列表和购物车信息，返回对应销售情况
        List<RankVO> cuisineRankList = getCuisineRankInfo(cuisineList,cartInfo);
        return cuisineRankList;
    }


    /**
     * 菜品销量排行
     * @param orderBy
     * @return
     */
    public List<RankVO> getDishRank(Integer orderBy) {
        List<OrderBill> billList = getOrderBillList(orderBy);
        //获取购物车信息
        List<CartVo> cartInfo = getCartInfo(billList);
        //获取所有菜品列表
        List<Dish> dishList = dishMapper.selectListByQuery(QueryWrapper.create().where(DISH.STATUS.eq(CommonEnum.STATUS_ON.getIntValue())));
        //遍历菜系列表和购物车信息，返回对应销售情况
        List<RankVO> dishrankList = getDishRankInfo(dishList,cartInfo);
        return dishrankList;
    }



    /**
     * 统计菜品，口味销量销售排行
     * @param orderBy
     * @return
     */
    public List<TasteRankVo> getTasteRank(Integer orderBy) {
        List<OrderBill> billList = getOrderBillList(orderBy);
        //获取购物车信息
        List<CartVo> cartInfo = getCartInfo(billList);
        //获取所有口味列表
        RelationManager.addExtraConditionParam("status",CommonEnum.STATUS_ON.getIntValue());
        List<DishVo> dishList = dishMapper.selectListWithRelationsByQueryAs(QueryWrapper.create().where(DISH.STATUS.eq(CommonEnum.STATUS_ON.getIntValue())),DishVo.class);
        //遍历菜品口味列表和购物车信息，返回对应销售情况
        List<TasteRankVo> tasteRankList = getTasteRankInfo(dishList,cartInfo);
        return tasteRankList;
    }



    /**
     * 月份统计
     * @return
     */
    public StatVo getMonthStat() {
        //构造月份列表
        YearMonth end = YearMonth.now();
        YearMonth start = ChronoUnit.MONTHS.addTo(end, -5);
        long size = ChronoUnit.MONTHS.between(start, end) + 1;
        List<String> monthList = Stream.iterate(start, month -> month.plusMonths(1)).limit(size).map(YearMonth::toString).collect(Collectors.toList());
        List<Integer> quantityList = new ArrayList<>();
        List<BigDecimal> customList = new ArrayList<>();
        StatVo stat = new StatVo();
        //循环遍历查询
        monthList.forEach(month->{
            OverallVo monthOverall = getOverallByOrderby(BillEnum.BILL_ORDER_BY_MONTH.getIntValue(), month);
            quantityList.add(monthOverall.getMonthQuantity());
            customList.add(monthOverall.getMonthCustom());
        });
        stat.setMonthList(monthList);
        stat.setQuantityList(quantityList);
        stat.setCustomList(customList);
        return stat;
    }

    /**
     * 前七天统计
     * @return
     */
    public StatVo getWeekStat() {
        //构造日期列表
        LocalDate end = LocalDate.now();
        LocalDate start = ChronoUnit.DAYS.addTo(end,-6);
        long limit = ChronoUnit.DAYS.between(start, end) + 1;
        List<String> dayList = Stream.iterate(start, day -> day.plusDays(1)).limit(limit).map(LocalDate::toString).collect(Collectors.toList());

        List<Integer> quantityList = new ArrayList<>();
        List<BigDecimal> customList = new ArrayList<>();
        StatVo stat = new StatVo();
        //遍历，获取销售情况
        dayList.forEach(day->{
            OverallVo dayOverall = getOverallByOrderby(BillEnum.BILL_ORDER_BY_DAY.getIntValue(), day);
            quantityList.add(dayOverall.getDayQuantity());
            customList.add(dayOverall.getDayCustom());
        });
        stat.setWeekList(dayList);
        stat.setQuantityList(quantityList);
        stat.setCustomList(customList);
        return stat;
    }

    /**
     * 价格区间排行统计
     */
    public List<PriceRangeVo> getPriceRangeRank(Integer orderBy) {
        //获取订单列表
        List<OrderBill> billList = getOrderBillList(orderBy);
        //获取购物车信息
        List<CartVo> cartInfo = getCartInfo(billList);

        List<Integer> priceRange = Arrays.asList(0,5,8,12,15,18,20,999999);
        List<PriceRangeVo> list = new ArrayList<>();
        for (int i = 0; i < priceRange.size()-1; i++) {
            BigDecimal start = new BigDecimal(priceRange.get(i));
            BigDecimal end = new BigDecimal(priceRange.get(i+1));
            PriceRangeVo priceRangeVo = new PriceRangeVo();
            final BigDecimal[] totalConsume = {BigDecimal.ZERO};
            final Integer[] totalQuantity = {0};
            cartInfo.stream().filter(cart->cart.getUnitPrice().compareTo(start)>0&&cart.getUnitPrice().compareTo(end)<=0).forEach(cart->{
                totalConsume[0] = totalConsume[0].add(cart.getPrice());
                totalQuantity[0] +=cart.getQuantity();
            });
            String pre = i==priceRange.size()-2?"+∞)":end+"]";
            priceRangeVo.setName("("+start+","+pre);
            priceRangeVo.setTotalCustom(totalConsume[0]);
            priceRangeVo.setTotalQuantity(totalQuantity[0]);
            list.add(priceRangeVo);
        }
        return list;
    }


    /**
     * 根据参数构造筛选条件
     *
     * @param orderBy
     * @param qw
     * @param time
     */
    private static void orderByType(Integer orderBy, QueryWrapper qw, String time) {
        if (time==null) time = "";
        //根据参数筛选
        switch (BillEnum.getByValue(orderBy)){
            case BILL_ORDER_BY_YEAR:
                if(StrUtil.isBlank(time)) time = Year.now().toString();
                qw.and(dateFormat(ORDER_BILL.CREATE_TIME,"%Y").eq(time));
                break;
            case BILL_ORDER_BY_MONTH:
                if (StrUtil.isBlank(time)) time = YearMonth.now().toString();
                qw.and(dateFormat(ORDER_BILL.CREATE_TIME,"%Y-%m").eq(time));
                break;
            case BILL_ORDER_BY_DAY:
                if (StrUtil.isBlank(time))time = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
                qw.and(dateFormat(ORDER_BILL.CREATE_TIME,"%Y-%m-%d").eq(time));
                break;
            case BILL_ORDER_BY_WEEK:

                qw.and(dateFormat(ORDER_BILL.CREATE_TIME,"%Y").eq(year(now()))).and(week(ORDER_BILL.CREATE_TIME).eq(week(now())));
                break;
        }
    }


    /**
     * 根据年月入日获取销售总览数据
     */
    private OverallVo getOverallByOrderby(Integer orderBy,String time) {
        QueryWrapper qw = QueryWrapper.create();
        switch (BillEnum.getByValue(orderBy)){
            case BILL_ORDER_BY_YEAR:
                qw.select(ifNull(sum(ORDER_BILL.PAY_PRICE), column("0")).as("yearCustom"),
                        ifNull(sum(ORDER_BILL.TOTAL_QUANTITY), column("0")).as("yearQuantity"));
                break;
            case BILL_ORDER_BY_MONTH:
                qw.select(ifNull(sum(ORDER_BILL.PAY_PRICE), column("0")).as("monthCustom"),
                        ifNull(sum(ORDER_BILL.TOTAL_QUANTITY), column("0")).as("monthQuantity"));
                break;
            case BILL_ORDER_BY_DAY:
                qw.select(ifNull(sum(ORDER_BILL.PAY_PRICE), column("0")).as("dayCustom"),
                        ifNull(sum(ORDER_BILL.TOTAL_QUANTITY), column("0")).as("dayQuantity"));
                break;
        }
        qw.where(ORDER_BILL.STATUS.eq(OrderEnum.ORDER_STATUS_FINISHED.getIntValue()));
        orderByType(orderBy,qw,time);
        OverallVo overall = orderBillMapper.selectOneByQueryAs(qw, OverallVo.class);
        return overall;
    }

    /**
     * 获取订单记录列表
     * @param orderBy
     * @return
     */
    private List<OrderBill> getOrderBillList(Integer orderBy) {
        QueryWrapper qw = QueryWrapper.create().where(ORDER_BILL.STATUS.eq(OrderEnum.ORDER_STATUS_FINISHED.getIntValue()));
        orderByType(orderBy,qw, null);
        List<OrderBill> billList = orderBillMapper.selectListByQuery(qw);
        return billList;
    }

    /**
     * 根据订单列表构造出购物车
     * @param billList
     * @return
     */
    private List<CartVo>  getCartInfo(List<OrderBill> billList) {
        List<CartVo> cartList = new ArrayList<>();
        billList.stream().forEach(bill->{
            String cartInfo = bill.getCartInfo();
            if (StrUtil.isNotBlank(cartInfo)){
                List<CartVo> cartVos = JSONArray.parseArray(cartInfo, CartVo.class);
                cartList.addAll(cartVos);
            }
        });
        return cartList;
    }


    /**
     * 根据菜系列表和购物车数据列表遍历菜系数据
     * @param cuisineList
     * @param cartInfo
     * @return
     */
    private List<RankVO> getCuisineRankInfo(List<Cuisine> cuisineList, List<CartVo> cartInfo) {
        List<RankVO> rankVOList = new ArrayList<>();
        cuisineList.forEach(cuisine -> {
            RankVO rankVO = new RankVO();
            final BigDecimal[] totalConsume = {BigDecimal.ZERO};
            final Integer[] totalQuantity = {0};
            cartInfo.stream().filter(cart-> cart.getDish().getCuisineId().equals(cuisine.getId())).forEach(cart->{
                totalConsume[0] = totalConsume[0].add(cart.getPrice());
                totalQuantity[0] +=cart.getQuantity();
            });
            rankVO.setName(cuisine.getName());
            rankVO.setTotalCustom(totalConsume[0]);
            rankVO.setTotalQuantity(totalQuantity[0]);
            rankVOList.add(rankVO);
        });
        List<RankVO> result = rankVOList.stream().filter(rank->!rank.getTotalQuantity().equals(0)).sorted(Comparator.comparing(RankVO::getTotalCustom).reversed()).collect(Collectors.toList());
        return result;
    }

    /**
     * 根据菜品列表和购物车数据列表遍历菜系数据
     * @param dishList
     * @param cartInfo
     * @return
     */
    private List<RankVO> getDishRankInfo(List<Dish> dishList, List<CartVo> cartInfo) {
        List<RankVO> rankVOList = new ArrayList<>();
        dishList.forEach(dish -> {
            RankVO rankVO = new RankVO();
            final BigDecimal[] totalConsume = {BigDecimal.ZERO};
            final Integer[] totalQuantity = {0};
            cartInfo.stream().filter(cart-> cart.getDishId().equals(dish.getId())).forEach(cart->{
                totalConsume[0] = totalConsume[0].add(cart.getPrice());
                totalQuantity[0] +=cart.getQuantity();
            });
            rankVO.setName(dish.getName());
            rankVO.setTotalCustom(totalConsume[0]);
            rankVO.setTotalQuantity(totalQuantity[0]);
            rankVOList.add(rankVO);
        });
        List<RankVO> result = rankVOList.stream().filter(rank->!rank.getTotalQuantity().equals(0)).sorted(Comparator.comparing(RankVO::getTotalCustom).reversed()).collect(Collectors.toList());
        return result;
    }


    /**
     *根据菜品口味列表和购物车数据列表遍历菜系数据
     * @param dishList
     * @param cartInfo
     * @return
     */
    private List<TasteRankVo> getTasteRankInfo(List<DishVo> dishList, List<CartVo> cartInfo) {
        List<TasteRankVo> rankVOList = new ArrayList<>();
        dishList.forEach(dish -> {
            dish.getItemList().forEach(taste -> {
                TasteRankVo rankVO = new TasteRankVo();
                final BigDecimal[] totalConsume = {BigDecimal.ZERO};
                final Integer[] totalQuantity = {0};
                cartInfo.stream().filter(cart-> cart.getDishId().equals(dish.getId())&&cart.getTasteId().equals(taste.getId())).forEach(cart->{
                    totalConsume[0] = totalConsume[0].add(cart.getPrice());
                    totalQuantity[0] +=cart.getQuantity();
                });
                rankVO.setName(taste.getName());
                rankVO.setTotalCustom(totalConsume[0]);
                rankVO.setTotalQuantity(totalQuantity[0]);
                rankVO.setDishName(dish.getName());
                rankVOList.add(rankVO);
            });
        });
        List<TasteRankVo> result = rankVOList.stream().filter(rank->!rank.getTotalQuantity().equals(0)).sorted(Comparator.comparing(RankVO::getTotalCustom).reversed()).collect(Collectors.toList());
        return result;
    }
    public static void main(String[] args) {

    }
}
